use std::{fs::File, io::Read};

use super::my_crypto::my_crypto;

use structopt::StructOpt;

#[derive(StructOpt, Debug)]
pub struct Opt {
    #[structopt(short, long, help = "Insert into mysql online, do not create sql file")]
    pub online: bool,

    #[structopt(long, help = "Do not record binlog")]
    pub no_log: bool,

    #[structopt(long, short, help = "Rest mysql connection per transaction")]
    pub reset: bool,

    #[structopt(
        long,
        default_value = "select 1 from dual",
        help = "select statement or txt file"
    )]
    pub sql: String,

    #[structopt(long, help = "Sql file", default_value = "temp.sql")]
    pub file: String,

    #[structopt(long, help = "Oracle host", default_value = "127.0.0.1")]
    pub oh: String,

    #[structopt(long, default_value = "system", help = "Oracle user")]
    pub ou: String,

    #[structopt(long, help = "Oracle password", default_value = "manager")]
    pub ok: String,

    #[structopt(long, default_value = "1521", help = "Oracle port")]
    pub op: u16,

    #[structopt(long, help = "Oracle server name", default_value = "orcl")]
    pub ob: String,

    #[structopt(long, help = "MySQL host")]
    pub th: Option<String>,

    #[structopt(long, help = "MySQL port", default_value = "3306")]
    pub tp: u16,

    #[structopt(long, help = "MySQL user", default_value = "root")]
    pub tu: String,

    #[structopt(long, help = "MySQL password")]
    pub tk: Option<String>,

    #[structopt(long, help = "MySQL database")]
    pub tb: Option<String>,

    #[structopt(long, help = "MySQL table", default_value = "test")]
    pub tt: String,

    #[structopt(long, help = "Number rows one sql", default_value = "10000")]
    pub row: u32,

    #[structopt(long, help = "Run sql before select")]
    pub pre_sql: Option<String>,

    #[structopt(long, help = "The key to be crypted", default_value = "password")]
    pub key: String,

    #[structopt(long, help = "Crypt key option")]
    pub crypt: bool,

    #[structopt(long, help = "Number sql one transaction", default_value = "1")]
    pub trans: u32,

    #[structopt(long, help = "Number thread to run sql for mysql", default_value = "1")]
    pub thread: u32,
}

impl Opt {
    pub fn init() -> Option<Opt> {
        let mut opt = Opt::from_args();

        if opt.crypt {
            println!("{}", my_crypto(&opt.key, true));
            return None;
        }

        if opt.online {
            if opt.th == None || opt.tk == None || opt.tb == None {
                return None;
            }
        } else {
            opt.thread = 1; // in file mode, thread must equal 1
        }

        if let None = opt.sql.find("select ") {
            let mut f = File::open(&opt.sql).unwrap();
            let mut buffer = String::new();
            f.read_to_string(&mut buffer).unwrap();
            opt.sql = buffer;
        }

        opt.ok = match base64::decode(&opt.ok) {
            Ok(_) => my_crypto(&opt.ok, false),
            Err(_) => opt.ok,
        };

        if let Some(p) = opt.tk {
            opt.tk = match base64::decode(&p) {
                Err(_) => Some(p),
                Ok(_) => Some(my_crypto(&p, false)),
            }
        };

        Some(opt)
    }
}
